 /*******************************************************************************
  * Copyright (c) 2005, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal;

 import java.util.Collection ;
 import java.util.HashMap ;
 import java.util.HashSet ;
 import java.util.Map ;

 import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.ui.IPropertyListener;
 import org.eclipse.ui.contexts.IContextActivation;
 import org.eclipse.ui.contexts.IContextService;
 import org.eclipse.ui.internal.registry.IActionSetDescriptor;
 import org.eclipse.ui.services.IServiceLocator;

 /**
  * Maintains a reference counted set of action sets, with a visibility mask.
  * This is used to determine the visibility of actions in a workbench page. In a
  * workbench page, there may be may be many conditions that can cause an action
  * set to become visible (such as the active part, the active editor, the
  * default visibility of the action, the properties of the perspective, etc.)
  * The user can also explicitly mask off particular action sets in each
  * perspective.
  * <p>
  * The reference count indicates how many conditions have requested that the
  * actions be active and the mask indicates whether or not the set was disabled
  * by the user.
  * </p>
  *
  * @since 3.1
  */
 public class ActionSetManager {

     private static class ActionSetRec {
         int showCount;

         int maskCount;
         
         public boolean isVisible() {
             return maskCount == 0 && showCount > 0;
         }
         
         public boolean isEmpty() {
             return maskCount == 0 && showCount == 0;
         }
     }

     private HashMap actionSets = new HashMap ();
     private HashSet visibleItems = new HashSet ();
     
     public static final int PROP_VISIBLE = 0;
     public static final int PROP_HIDDEN = 1;
     public static final int CHANGE_MASK = 0;
     public static final int CHANGE_UNMASK = 1;
     public static final int CHANGE_SHOW = 2;
     public static final int CHANGE_HIDE = 3;
     
     private ListenerList listeners = new ListenerList();
     private IPropertyListener contextListener;
     private Map activationsById = new HashMap ();
     private IContextService contextService;
     
     public ActionSetManager(IServiceLocator locator) {
         contextService = (IContextService) locator.getService(IContextService.class);
         addListener(getContextListener());
     }
     
     /**
      * @return
      */
     private IPropertyListener getContextListener() {
         if (contextListener == null) {
             contextListener = new IPropertyListener() {
                 public void propertyChanged(Object source, int propId) {
                     if (source instanceof IActionSetDescriptor) {
                         IActionSetDescriptor desc = (IActionSetDescriptor) source;
                         String id = desc.getId();
                         if (propId == PROP_VISIBLE) {
                             activationsById.put(id, contextService
                                     .activateContext(id));
                         } else if (propId == PROP_HIDDEN) {
                             IContextActivation act = (IContextActivation) activationsById
                                     .remove(id);
                             if (act != null) {
                                 contextService.deactivateContext(act);
                             }
                         }
                     }
                 }
             };
         }
         return contextListener;
     }

     public void addListener(IPropertyListener l) {
         listeners.add(l);
     }

     public void removeListener(IPropertyListener l) {
         listeners.remove(l);
     }
     
     private void firePropertyChange(IActionSetDescriptor descriptor, int id) {
         Object [] l = listeners.getListeners();
         for (int i=0; i<l.length; i++) {
             IPropertyListener listener = (IPropertyListener) l[i];
             listener.propertyChanged(descriptor, id);
         }
     }
     
     private ActionSetRec getRec(IActionSetDescriptor descriptor) {
         ActionSetRec rec = (ActionSetRec)actionSets.get(descriptor);
         
         if (rec == null) {
             rec = new ActionSetRec();
             actionSets.put(descriptor, rec);
         }
         
         return rec;
     }
     
     public void showAction(IActionSetDescriptor descriptor) {
         ActionSetRec rec = getRec(descriptor);
         
         boolean wasVisible = rec.isVisible();
         rec.showCount++;
         if (!wasVisible && rec.isVisible()) {
             visibleItems.add(descriptor);
             firePropertyChange(descriptor, PROP_VISIBLE);
             if (rec.isEmpty()) {
                 actionSets.remove(descriptor);
             }
         }
     }
     
     public void hideAction(IActionSetDescriptor descriptor) {
         ActionSetRec rec = getRec(descriptor);
         
         boolean wasVisible = rec.isVisible();
         rec.showCount--;
         if (wasVisible && !rec.isVisible()) {
             visibleItems.remove(descriptor);
             firePropertyChange(descriptor, PROP_HIDDEN);
             if (rec.isEmpty()) {
                 actionSets.remove(descriptor);
             }
         }
     }
     
     public void maskAction(IActionSetDescriptor descriptor) {
         ActionSetRec rec = getRec(descriptor);
         
         boolean wasVisible = rec.isVisible();
         rec.maskCount++;
         if (wasVisible && !rec.isVisible()) {
             visibleItems.remove(descriptor);
             firePropertyChange(descriptor, PROP_HIDDEN);
             if (rec.isEmpty()) {
                 actionSets.remove(descriptor);
             }
         }
     }
     
     public void unmaskAction(IActionSetDescriptor descriptor) {
         ActionSetRec rec = getRec(descriptor);
         
         boolean wasVisible = rec.isVisible();
         rec.maskCount--;
         if (!wasVisible && rec.isVisible()) {
             visibleItems.add(descriptor);
             firePropertyChange(descriptor, PROP_VISIBLE);
             if (rec.isEmpty()) {
                 actionSets.remove(descriptor);
             }
         }
     }
     
     public Collection getVisibleItems() {
         return visibleItems;
     }
     
     public void change(IActionSetDescriptor descriptor, int changeType) {
         switch(changeType) {
         case CHANGE_SHOW:
             showAction(descriptor); break;
         case CHANGE_HIDE:
             hideAction(descriptor); break;
         case CHANGE_MASK:
             maskAction(descriptor); break;
         case CHANGE_UNMASK:
             unmaskAction(descriptor); break;
         }
     }
 }

